package SSF.OS.OSPFv2.test;

/**
  * IPwithErrorInjection.java
  *
  * @author Dirk Jacob
  * @version 0.2.1
  */
 
import java.util.*;
import com.renesys.raceway.DML.*;
import com.renesys.raceway.SSF.*; 
 
/** This class is a replacement for SSF.OS.IP. Basic functionality is 
  * provided by IP and UnreliableIP, which provides the facility to
  * bring down links at given times. This class additionally provides
  * the facility to manipulate the contents of OSPF packets at given
  * times. More details are provided in the additional documentation of
  * the OSPF testsuite.
  */
public class IPwithErrorInjection extends UnreliableIP {
	
	/** Container to specify errors */
    class OSPFError {
    	/** start time */
		public double from;
		/** end time */
		public double until;
		/** interface */
		public int ifc;
		/** error parameters */
		public Hashtable parameters;
    }
	
	/** a vector with all the specified errors */
    private Vector errors;
    
    /** referece to the log utility */
    private Logger log = null;
	
	/** Constructor */
    public IPwithErrorInjection() {
		super();
		
		errors = new Vector();
		log = new Logger(Logger.DEBUG_NONE, this, "IPwithErrorInjection");
    }
	
	/** Configures this ProtocolSession
	  * <pre>
	  * ProtocolSession[ name ip use SSF.OS.OSPFv2.test.IPwithErrorInjection
	  *         error [
	  *             from <time>
	  *             until <time>
	  *             interface <id>
	  *             netmask <mask>
	  *         ]
	  *         error [
	  *             from <time>
	  *             until <time>
	  *             interface <id>
	  *             bad_age <age>
	  *         ]
	  *         error [
	  *             from <time>
	  *             until <time>
	  *             interface <id>
	  *             dd_mtu <mtu>
	  *         ]
	  * ]
	  * </pre>
	  */
    @Override
	public void config(Configuration cfg) throws configException {
        
       	/* first configure the standard IP class */
		super.config(cfg);
	
		/* now configure the log utility */
		log.config( cfg );
		
		/* now, look for configured errors */
		for( Enumeration d = cfg.find("error"); d.hasMoreElements(); ) {
		
	    	Configuration dcfg = (Configuration)d.nextElement();

	    	String from = (String)dcfg.findSingle("from");
	    	String until = (String)dcfg.findSingle("until");
	    	String ifc = (String)dcfg.findSingle("interface");

            /* only completely specified configs are taken */
	    	if( (from != null) && (until != null) && (ifc != null)) {
		
				/* create an Error object for the specific error */
				OSPFError err = new OSPFError();
			
				err.from = Double.parseDouble( from );
				err.until = Double.parseDouble( until );
				err.ifc = Integer.parseInt( ifc );
				
				err.parameters = new Hashtable();
				
				String str;
				
				str = (String)dcfg.findSingle("netmask");
				if(str != null) {
		    		err.parameters.put("netmask", str);
				}
				str = (String)dcfg.findSingle("bad_age");
					if(str != null) {
		    		err.parameters.put("bad_age", str);
				}
				str = (String)dcfg.findSingle("dd_mtu");
				if(str != null)  {
		    		err.parameters.put("dd_mtu", str);
				}
								
				/* and store it in the vector */
				errors.addElement( err );
	    	}
		}
    }
	
	/** Handles incoming and outgoing IP-packets. Dependent of the interface
	  * and the simulation time, the packets are dropped or simply passed to
	  * UnreliableIP.
	  */
    public boolean push(ProtocolMessage message, ProtocolSession fromSession) throws ProtocolException {
		
		if(fromSession instanceof OSPF) {
	    	IpHeader ipHeader = (IpHeader)message;

	    	/* look how late it is now ;) */
	    	double actual_time = (inGraph().now()) / SSF.Net.Net.frequency;
	
	    	/* walk through errors and modify the packet accordingly */
	    	for (Enumeration e = errors.elements(); e.hasMoreElements(); ) {

	    		OSPFError act = (OSPFError)e.nextElement();

	    		if( (act.from <= actual_time) && (act.until >= actual_time) ) {
	    	
	    	    	RoutingInfo rtgInfo = ROUTING_TABLE.findBest(ipHeader.SOURCE_IP,ipHeader.DEST_IP);
      		
      		    	if (rtgInfo != null) {
      					NIC use_iface = rtgInfo.next_hop_interface();
      			
      					if(act.ifc == use_iface.ID) {
      			    		for(Enumeration k = act.parameters.keys(); k.hasMoreElements();) {
      			    			String key = (String)k.nextElement();
      			    	
      			    			String value = (String)act.parameters.get(key);
      			    	
      			    			if(key == "netmask") {
      			    	    		Packet ospfPkt = (Packet)ipHeader.payload();
      			    	    		if(ospfPkt.type == Packet.HELLO) {
      			    	    			HelloPacket helloPkt = (HelloPacket)ospfPkt.payload();
      			    	    	
      			    	    			helloPkt.netMask = IP_s.StrToInt(value);
      			    	    			log.logMessage("inserted netmask error!");
      			    	    		}
      							}
      							if(key == "dd_mtu") {
      				    			Packet ospfPkt = (Packet)ipHeader.payload();
      				    			if(ospfPkt.type == Packet.DATABASE) {
      				    				DD_Packet ddPkt = (DD_Packet)ospfPkt.payload();
      				    	
		      				    		ddPkt.interfaceMTU = Integer.parseInt(value);
    		  				    		log.logMessage("inserted bad MTU!");
      						    	}
      							}
      							if(key == "bad_age") {
      								Packet ospfPkt = (Packet)ipHeader.payload();
      								if(ospfPkt.type == Packet.LSUPDATE) {
      									LS_UpdatePacket updPkt = (LS_UpdatePacket)ospfPkt.payload();
      								
	      								Vector updLsas = updPkt.getLSAs();
    	  								for(Enumeration l = updLsas.elements(); l.hasMoreElements();) {
      										LSA lsa = (LSA)l.nextElement();
      										lsa.lsAge = Integer.parseInt(value);
      										log.logMessage("inserted bad lsAge!");
      									}	
      								}
      							}	
      			    		}
      					}
      		    	}
	    		}
	    	}
		}	
		
		/* Call the handler of the superclass to do further processing
	  	   of the packet */
		return super.push(message, fromSession);
    }	
}
